/*******************************************************************************
 * File name  : thread_watchdog.c
 *------------------------------------------------------------------------------
 * Project    : common
 *------------------------------------------------------------------------------
 * Author(s)  : Jimmy.Cui
 *------------------------------------------------------------------------------
 * Copyright (c) 2021 Jimmy.
 * All rights reserved.
 *******************************************************************************/

/********************************************************************************
 * Included header
 *******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include "thread_watchdog.h"

/********************************************************************************
 * Local constants and macros (private to module)
 *******************************************************************************/

/********************************************************************************
 * Local data types (private typedefs / structs / enums)
 *******************************************************************************/

/********************************************************************************
 * Local data (private to module)
 *******************************************************************************/
static threadWd *sHead = NULL;
static threadWd *sTail = NULL;  /* 添加尾指针提高插入效率 */
static pthread_mutex_t sMutex = PTHREAD_MUTEX_INITIALIZER;  /* 线程安全保护 */

/********************************************************************************
 * Local function prototypes (private to module)
 *******************************************************************************/

/********************************************************************************
 * Global data (private to projection)
 *******************************************************************************/

/********************************************************************************
 * Local functions (private to module)
 *******************************************************************************/

/********************************************************************************
 * Local functions (extern)
 *******************************************************************************/
void threadWd_Create(threadWd **pp)
{
    threadWd *pNewNode = NULL;
    
    /* 参数检查 */
    if (pp == NULL)
    {
        return;
    }
    
    /* 分配内存并检查是否成功 */
    pNewNode = (threadWd *)malloc(sizeof(threadWd));
    if (pNewNode == NULL)
    {
        *pp = NULL;
        return;
    }
    
    /* 初始化新节点 */
    pNewNode->eWdStatus = E_FEED_DOG;
    pNewNode->next = NULL;
    
    /* 线程安全保护 */
    pthread_mutex_lock(&sMutex);
    
    if (sHead == NULL)
    {
        /* 链表为空，新节点作为头节点 */
        sHead = pNewNode;
        sTail = pNewNode;
    }
    else
    {
        /* 链表不为空，添加到尾部（使用尾指针提高效率） */
        sTail->next = pNewNode;
        sTail = pNewNode;
    }
    
    pthread_mutex_unlock(&sMutex);
    
    *pp = pNewNode;
}

void threadWd_FeedDog(threadWd *p)
{
    /* 参数检查 */
    if (p == NULL)
    {
        return;
    }
    
    p->eWdStatus = E_FEED_DOG;
}

void threadWd_Exit(threadWd **pp)
{
    threadWd *pCurrent = NULL;
    threadWd *pPrevious = NULL;
    
    /* 参数检查 */
    if (pp == NULL || *pp == NULL)
    {
        return;
    }
    
    /* 线程安全保护 */
    pthread_mutex_lock(&sMutex);
    
    if (sHead == NULL)
    {
        pthread_mutex_unlock(&sMutex);
        return;
    }
    
    pCurrent = sHead;
    pPrevious = NULL;
    
    /* 查找要删除的节点 */
    while (pCurrent != *pp && pCurrent->next != NULL)
    {
        pPrevious = pCurrent;
        pCurrent = pCurrent->next;
    }
    
    if (pCurrent == *pp)
    {
        /* 找到要删除的节点 */
        if (pCurrent == sHead)
        {
            /* 删除头节点 */
            sHead = pCurrent->next;
            if (sHead == NULL)
            {
                sTail = NULL;  /* 链表变空，更新尾指针 */
            }
        }
        else
        {
            /* 删除中间或尾节点 */
            pPrevious->next = pCurrent->next;
            if (pCurrent == sTail)
            {
                sTail = pPrevious;  /* 更新尾指针 */
            }
        }
        
        free(pCurrent);
        *pp = NULL;
    }
    
    pthread_mutex_unlock(&sMutex);
}

void threadWd_Check(void)
{
    threadWd *pCurrent = NULL;
    
    /* 线程安全保护 */
    pthread_mutex_lock(&sMutex);
    
    pCurrent = sHead;
    while (pCurrent != NULL)
    {
        if (pCurrent->eWdStatus == E_CLEAN)
        {
            /* 发现未喂狗的线程，退出程序 */
            pthread_mutex_unlock(&sMutex);
            exit(-1);
        }
        pCurrent->eWdStatus = E_CLEAN;
        pCurrent = pCurrent->next;
    }
    
    pthread_mutex_unlock(&sMutex);
}

void threadWd_Cleanup(void)
{
    threadWd *pCurrent = NULL;
    threadWd *pNext = NULL;
    
    /* 线程安全保护 */
    pthread_mutex_lock(&sMutex);
    
    pCurrent = sHead;
    while (pCurrent != NULL)
    {
        pNext = pCurrent->next;
        free(pCurrent);
        pCurrent = pNext;
    }
    
    sHead = NULL;
    sTail = NULL;
    
    pthread_mutex_unlock(&sMutex);
}

/*---------------------------------- End of the file ---------------------------------*/
